package stack

import (
	"io"
	"text/template"
)

type keyValue struct {
	Key   string
	Value string
}

type Service struct {
	Ports       []keyValue
	Environment []keyValue
}

type LiteExplorer struct {
	Explorer       Service
	FaucetFrontend Service
	FaucetBackend  Service
}

type EthExplorer struct {
	Port     string
	JRPCHttp string
	JRPCWs   string
}

type BFT3 struct {
	ConfigTmpl string
	Chaincode  string
	Chainname  string

	Peers []Peer
}

type Peer struct {
	Name         string
	CliName      string
	PortMappings []PortMapping
}

type BFT2 struct {
	DeployResources []DeployResource
}

type DAG struct {
	Project    string
	NumOfNodes int
	Network    string

	Nodes []DagNode
}

type DagNode struct {
	Name  string // mixin-1,mixin-2....
	Dir   string // /tmp/{your project}/mixin-686%d starting from i,  eg./tmp/myproj/mixin-6861,/tmp/kk/mixin-6862.../tmp/kk/mixin-68611
	Ports string // host port:686%d starting from 1, eg. 18611:6862  18611:6862

	Environments    []Environment
	Volumes         []Volume
	DeployResources []DeployResource
}

type POS = POA
type POW = POA
type POW2 = POA
type NS3 = POA
type NS3POA2 = POA
type NS3POW2 = POW2

type POA struct {
	Name    string
	Nfs     string
	Network string
	Nodes   []Node

	GethCmdOpt string
}

type SoloPOS SoloPOS2
type SoloPOS2 struct {
	Nfs string

	BeaconChainNodes []Node // beacon-chain node in pos
	// Name beacon-chain
	// PortMappings 4000
	// CommandOptions execution-endpoint=http://geth:8551

	Nodes []Node // geth node in pos
	// Name geth
	// PortMappings 8551,8545, 8546

	ValidatorNodes []Node // validator node in pos
	// Name validator
	// CommandOptions beacon-rpc-provider=beacon-chain:4000
}

type DeployResource struct {
	LimitsOrReservations string
	HowMuchReses         []HowMuchRes
}

type HowMuchRes struct {
	Res     string
	HowMuch string
}

type Node struct {
	Name         string
	PortMappings []PortMapping
	Account      string
	SINGER       bool

	Environments    []Environment
	Volumes         []Volume
	DeployResources []DeployResource

	CommandOptions []CommandOption

	DependOns []DependOn
}

type DependOn struct {
	Name      string
	Condition string
}

type CommandOption struct {
	Name  string
	Value string
}

type Volume struct {
	Source      string
	Destination string
}

type Environment struct {
	Name  string
	Value string
}

type PortMapping struct {
	Target      int
	Destination int
}

func ParseDAGTemplate(wr io.Writer, path string, data DAG) error {
	return parseTemplate(wr, path, data)
}

func ParsePOATemplate(wr io.Writer, path string, data POA) error {
	return parseTemplate(wr, path, data)
}

func ParsePOS2Template(wr io.Writer, path string, data SoloPOS2) error {
	return parseTemplate(wr, path, data)
}

func ParsePOSTemplate(wr io.Writer, path string, data SoloPOS) error {
	return parseTemplate(wr, path, data)
}

func ParsePOAGenesisTemplate(wr io.Writer, path string, data struct{ ANumberOfAddressesHex string }) error {
	return parseTemplate(wr, path, data)
}

func ParsePFT3Template(wr io.Writer, path string, data BFT3) error {
	return parseTemplate(wr, path, data)
}

func ParseBFT2Template(wr io.Writer, path string, data BFT2) error {
	return parseTemplate(wr, path, data)
}

func ParseEthExplorerTemplate(wr io.Writer, path string, data EthExplorer) error {
	return parseTemplate(wr, path, data)
}

func ParseLiteExplorerTemplate(wr io.Writer, path string, data LiteExplorer) error {
	return parseTemplate(wr, path, data)
}

func ParseNs3Template(wr io.Writer, path string, data NS3) error {
	return parseTemplate(wr, path, data)
}

func parseTemplate(wr io.Writer, path string, data any) error {
	tmplEngine, err := template.ParseFiles(path)
	if err != nil {
		return err
	}

	err = tmplEngine.Execute(wr, data)
	if err != nil {
		return err
	}

	return nil
}
